//
//  LQBaseObject.m
//  LQBaseKit
//
//  Created by 戴志朋 on 15/10/26.
//  Copyright © 2015年 hzdracom. All rights reserved.
//

#import "LQBaseObject.h"
#import <objc/runtime.h>
#import <NSDictionary+Path.h>
#import <NSObject+Utils.h>

@implementation LQBaseObject

+ (id)parserDic:(NSDictionary *)data
{
    return [[self new] initWithDictionary:data];
}

- (id)initWithDictionary:(NSDictionary *)data
{
    return [self parserFromDictionary:data];
}

- (id)parserFromFieldArray:(NSArray *)array
{
    NSDictionary *dictionaryKeysToPropertyKeys = [self dictionaryKeysToPropertyKeys];
    for (NSDictionary *dic in array) {
        NSString * name = dic[@"name"];
        id value = dic[@"value"];
        NSString * propertyName = dictionaryKeysToPropertyKeys[name];
        if (propertyName) {
            if ([value isKindOfClass:[NSNull class]]) {
                [self setValue:@(0) forKey:propertyName];
            } else {
                if([value isEqualToString:@"true"]||[value isEqualToString:@"false"]){
                    value = @([value boolValue]);
                }
                [self setValue:value forKey:propertyName];
            }
        }
    }
    return self;
}

- (id)parserFromDictionary:(NSDictionary *)dataDic
{
    if ([dataDic isKindOfClass:[NSArray class]]) {
        NSMutableArray * arry = [[NSMutableArray alloc]init];
        for (NSDictionary * dic in dataDic) {
            [arry addObject:[[self class] parserDic:dic]];
        }
        return arry;
    }
    NSDictionary *dictionaryKeysToPropertyKeys = [self dictionaryKeysToPropertyKeys];
    for (NSString *key in dataDic) {
        NSString *usedKey = key;
        NSString *propertyKey = dictionaryKeysToPropertyKeys[key];
        if (propertyKey) {
            usedKey = propertyKey;
        }
        if ([self respondsToSelector:NSSelectorFromString(usedKey)]) {
            
            NSString *className = [self getPropertyTypeString:usedKey];
            // not primitive types
            if (className) {
                Class class = NSClassFromString(className);
                if ([class isSubclassOfClass:[LQBaseObject class]]) {
                    
                    if (![[dataDic objectForPath:key] isKindOfClass:[NSNull class]]) {
                        // if the property is SRBaseModel's subclass
                        // init it with the right class
                        
                        LQBaseObject *value = [[class alloc] initWithDictionary:[dataDic objectForPath:key]];
                        [self setValue:value forKey:usedKey];
                    }
                } else {
                    //处理解析NSNull的情况
                    if ([[dataDic objectForPath:key] isKindOfClass:[NSNull class]]) {
                        [self setValue:@(0) forKey:usedKey];
                    }else{
                        [self setValue:[dataDic objectForPath:key] forKey:usedKey];
                    }
                }
            } else {
                // just set value directly
                // Null值如果直接设置会报错，所以这里处理了一下
                if ([[dataDic objectForPath:key] isKindOfClass:[NSNull class]]) {
                    [self setValue:@(0) forKey:usedKey];
                } else {
                    if ([[dataDic objectForPath:key] isKindOfClass:[NSString class]] && ([[dataDic objectForPath:key] isEqualToString:@"true"]||[[dataDic objectForPath:key] isEqualToString:@"false"])) {
                        [self setValue:[NSNumber numberWithBool:[[dataDic objectForPath:key] boolValue]] forKey:usedKey];
                    }else {
                        if ([[dataDic objectForPath:key] isKindOfClass:[NSDictionary class]]) {
                            [self setValue:@(0) forKey:usedKey];
                        }else {
                            [self setValue:[dataDic objectForPath:key] forKey:usedKey];
                        }
                        
                    }
                    
                }
            }
        }
        
    }
    return self;
}


- (NSString *)getPropertyTypeString:(NSString *)propertyName
{
    objc_property_t property = class_getProperty([self class], [propertyName UTF8String]);
    // propertyAttributes looks like: T@"NSArray",&,Vstuff
    const char * propertyAttributes = property_getAttributes(property);
    // suck out the type within attributes
    NSArray *sections = [[NSString stringWithUTF8String:propertyAttributes] componentsSeparatedByString:@"\""];
    NSString *type;
    if (sections.count == 3) {
        type = sections[1];
    }
    return type;
}

- (NSDictionary *)dictionaryKeysToPropertyKeys
{
    return @{};
}

- (NSString *)description
{
    return [self autoDescription];
}

#pragma mark - NSCoding
- (void)encodeWithCoder:(NSCoder *)aCoder
{
    unsigned int propertyCount;
    objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
    
    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = properties[i];
        char *propertyType = property_copyAttributeValue(property, "T");
        NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
        char *iVar = property_copyAttributeValue(property, "V");
        NSString *iVarName = [NSString stringWithFormat:@"%s", iVar];
        free(iVar);
        
        @try {
            switch (propertyType[0]) {
                case 'i': // int
                case 's': // short
                case 'l': // long
                case 'q': // long long
                case 'I': // unsigned int
                case 'S': // unsigned short
                case 'L': // unsigned long
                case 'Q': // unsigned long long
                case 'f': // float
                case 'd': // double
                case 'B': // BOOL
                    [aCoder encodeInteger:[[self valueForKey:iVarName] intValue] forKey:propertyName];
                    break;
                default:
                    [aCoder encodeObject:[self valueForKey:iVarName] forKey:propertyName];
            }
        }
        @catch (NSException *exception) {
            NSLog(@"encodeException:%@", exception);
        }
        free (propertyType);
    }
    free(properties);
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    if (self = [super init]) {
        unsigned int propertyCount;
        objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
        
        for (int i = 0; i < propertyCount; i++) {
            objc_property_t property = properties[i];
            char *propertyType = property_copyAttributeValue(property, "T");
            NSString *propertyName = [NSString stringWithFormat:@"%s", property_getName(property)];
            char *iVar = property_copyAttributeValue(property, "V");
            NSString *iVarName = [NSString stringWithFormat:@"%s", iVar];
            free(iVar);
            
            @try {
                switch (propertyType[0]) {
                    case 'i': // int
                    case 's': // short
                    case 'l': // long
                    case 'q': // long long
                    case 'I': // unsigned int
                    case 'S': // unsigned short
                    case 'L': // unsigned long
                    case 'Q': // unsigned long long
                    case 'f': // float
                    case 'd': // double
                    case 'B': // BOOL
                        [self setValue:[NSNumber numberWithInteger:[aDecoder decodeIntegerForKey:propertyName]] forKey:iVarName];
                        break;
                    default:
                        [self setValue:[aDecoder decodeObjectForKey:propertyName] forKey:iVarName];
                }
            }
            @catch (NSException *exception) {
                NSLog(@"setValueException:%@", exception);
            }
            free(propertyType);
        }
        free(properties);
    }
    return self;
}


#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone
{
    id object = [[[self class] allocWithZone:zone] init];
    
    unsigned int propertyCount;
    objc_property_t *properties = class_copyPropertyList([self class], &propertyCount);
    
    for (int i = 0; i < propertyCount; i++) {
        objc_property_t property = properties[i];
        char * attributeValue = property_copyAttributeValue(property, "V");
        NSString *iVarName = [NSString stringWithFormat:@"%s", attributeValue];
        free(attributeValue);
        [object setValue:[self valueForKey:iVarName] forKey:iVarName];
    }
    free(properties);
    return object;
}

@end
